/*
 * jxSwing Project (2014)
 * 
 * by Denilson Edinaldo Pinto
 * 
 * LGPL
 * Copyright (C) 2014
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.jxSwing.component.table.cellEditor;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

import javax.swing.DefaultCellEditor;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.UIManager;

import org.jxSwing.component.dialog.Dialog;
import org.jxSwing.component.dialog.ImageDialog;
import org.jxSwing.component.panel.BeanTablePanel;
import org.jxSwing.component.table.BeanTable;
import org.jxSwing.component.table.BeanTableColumn;
import org.jxSwing.i18n.I18N;
import org.jxUtils.TypeUtil;
import org.jxUtils.image.ImageUtil;

/**
 * @author Denilson Edinaldo Pinto
 * @porject jxSwing
 * @package org.jxSwing.component.table.cellEditor
 * @date 01/04/2014 - 19:14:55
 */
public class BeanEditor extends DefaultCellEditor {
	
	private static final long serialVersionUID = -4623232339022803480L;
	
	private static final int DEFAULT_HEIGHT = 25;
	
	private static final int DEFAULT_WIDTH = 50;
	
	protected BeanEditorPanel beanEditorPanel;
	
	private final String text;
	
	private Image frameIcon;
	
	private boolean firstRun = true;
	
	private Object value;
	
	private Dimension sizeToDialog = new Dimension(500, 350);
	
	/**
	 * @param text
	 */
	public BeanEditor(final String text) {
	
		super(new JTextField());
		
		this.text = text;
		
		beanEditorPanel = new BeanEditorPanel(text);
		
		beanEditorPanel.getButton().addMouseListener(new MouseAdapter() {
			
			@Override
			public void mouseClicked(final MouseEvent mouseEvent) {
			
				fireEditingStopped();
			}
		});
		
		beanEditorPanel.getLabel().addMouseListener(new MouseAdapter() {
			
			@Override
			public void mouseClicked(final MouseEvent mouseEvent) {
			
				fireEditingStopped();
			}
		});
	}
	
	/**
	 * @param value
	 * @param table
	 * @param column
	 * @return label
	 */
	private String getLabel(final Object value, final JTable table, final int column) {
	
		//
		if(value != null) {
			
			//
			if(value instanceof Collection<?>) {
				
				final Collection<?> collection = (Collection<?>)value;
				
				//
				if(collection.isEmpty()) {
					
					return null;
					
				}else {
					
					return table.getColumnName(column);
				}
				
			}else if(value instanceof Map<?, ?>) {
				
				final Map<?, ?> map = (Map<?, ?>)value;
				
				//
				if(map.isEmpty()) {
					
					return null;
					
				}else {
					
					return table.getColumnName(column);
				}
				
			}else {
				
				final String labelAux = value.toString();
				
				//
				if(labelAux != null && !labelAux.contains(value.getClass().getName() + "@" + Integer.toHexString(value.hashCode()))) {
					
					return labelAux;
				}
			}
			
		}else {
			
			return null;
		}
		
		return text;
	}
	
	/**
	 * @param container
	 * @return {@link Window} or <b>null</b>
	 */
	private Window getOwnerWindow(final Container container) {
	
		//
		if(container instanceof Window) {
			
			return (Window)container;
			
		}else {
			
			return getOwnerWindow(container.getParent());
		}
	}
	
	/**
	 * @param container
	 * @return {@link Image} or <b>null</b>
	 */
	private Image getOwnerWindowIcon(final Container container) {
	
		//
		if(container instanceof Window) {
			
			final Window window = (Window)container;
			
			return window.getIconImages().size() > 0 ? window.getIconImages().get(0) : null;
			
		}else {
			
			return getOwnerWindowIcon(container.getParent());
		}
	}
	
	/**
	 * @param table
	 * @return {@link Image} or <b>null</b>
	 */
	private Image getOwnerWindowIcon(final JTable table) {
	
		return getOwnerWindowIcon(table.getParent());
	}
	
	/**
	 * @param owner 
	 * @param beanTable
	 * @param column
	 */
	protected void action(final Window owner, final BeanTable<?> beanTable, final int column) {
	
		final BeanTableColumn beanTableColumn = beanTable.getColumn(column);
		
		//
		if(getValue() != null) {
			
			BeanTablePanel<?> tablePanel = null;
			
			Collection<?> values = null;
			
			// Se for uma Lista
			if(getValue() instanceof Collection<?>) {
				
				values = (Collection<?>)getValue();
				
				//
				if( !values.isEmpty()) {
					
					final Object firstValue = values.iterator().next();
					
					// Se o Tipo da Coluna é um primitivo
					if(TypeUtil.isPrimitive(firstValue.getClass()) || TypeUtil.isImageIcon(firstValue)) {
						
						tablePanel = new BeanTablePanel<>(beanTableColumn, values);
						
					}else {
						
						tablePanel = new BeanTablePanel<>(values);
					}
					
					setValue(tablePanel.getRows());
					
				}else {
					
					JOptionPane.showMessageDialog(null, I18N.component().thereAreNoDetails(), beanTableColumn.getAlias(), JOptionPane.INFORMATION_MESSAGE);
					
					return;
				}
				
			}else if(getValue() instanceof Map) {
				
				values = new ArrayList<>(((Map<?, ?>)getValue()).values());
				
				tablePanel = new BeanTablePanel<>(values);
				
			}else if(TypeUtil.isImageIcon(getValue())) {
				
				final ImageIcon imageIcon = (ImageIcon)getValue();
				
				String title;
				
				//
				if(imageIcon.getDescription() != null && !imageIcon.getDescription().trim().isEmpty()) {
					
					title = imageIcon.getDescription();
					
				}else {
					
					title = beanTableColumn.getAlias();
				}
				
				final ImageDialog imageDialog = new ImageDialog(owner, title, imageIcon, true);
				
				//
				if(frameIcon != null) {
					
					imageDialog.setIconImage(frameIcon);
				}
				
				imageDialog.showExitQuestion(false);
				imageDialog.setModal(true);
				imageDialog.centralize();
				
				return;
				
			}else {
				
				tablePanel = new BeanTablePanel<>(getValue());
				
				setValue(tablePanel.getRows());
			}
			
			//
			if(beanTable.isLocked()) {
				
				tablePanel.locked();
				
			}else {
				
				tablePanel.unLocked();
			}
			
			//
			tablePanel.showLineNumber(beanTable.showLineNumber());
			
			Container parent = beanTable.getParent();
			
			BeanTablePanel<?> beanTablePanelParent = null;
			
			//
			while(parent != null) {
				
				//
				if(parent.getClass().isAssignableFrom(BeanTablePanel.class)) {
					
					beanTablePanelParent = (BeanTablePanel<?>)parent;
					
					break;
					
				}else {
					
					parent = parent.getParent();
				}
			}
			
			//
			if(beanTablePanelParent != null) {
				
				tablePanel.setVisibleCrudButtons(beanTablePanelParent.isVisibleAdd(), beanTablePanelParent.isVisibleEdit(), beanTablePanelParent.isVisibleRemove());
				tablePanel.setVisibleExport(beanTablePanelParent.isVisibleExport());
				tablePanel.setVisibleFilter(beanTablePanelParent.isVisibleFilter());
				tablePanel.setVisiblePrint(beanTablePanelParent.isVisiblePrint());
				tablePanel.setVisibleAutoResizeColumns(beanTablePanelParent.isVisibleAutoResizeColumns());
				
				tablePanel.setEnabledCrudButtons(beanTablePanelParent.isEnabledCrudButtons());
				tablePanel.getHeaderBar().getBtnEdit().setEnabled(false);
				tablePanel.getHeaderBar().getBtnExport().setEnabled(beanTablePanelParent.isEnabledExport());
				tablePanel.getHeaderBar().getBtnFilter().setEnabled(beanTablePanelParent.isEnabledFilter());
				tablePanel.getHeaderBar().getBtnPrint().setEnabled(beanTablePanelParent.isEnabledPrint());
				tablePanel.getHeaderBar().getBtnAutoResizeColumns().setEnabled(beanTablePanelParent.isEnabledAutoResizeColumns());
				
				tablePanel.setAutoResizeColumns(beanTablePanelParent.getHeaderBar().getBtnAutoResizeColumns().isSelected());
				
			}else {
				
				tablePanel.setVisibleCrudButtons(false);
				tablePanel.setVisibleExport(false);
				tablePanel.setVisibleFilter(false);
				tablePanel.setVisiblePrint(false);
				tablePanel.setVisibleAutoResizeColumns(true);
				
				tablePanel.setEnabledCrudButtons(false);
				tablePanel.setEnabledExport(false);
				tablePanel.setEnabledFilter(false);
				tablePanel.setEnabledPrint(false);
				tablePanel.setEnabledAutoResizeColumns(true);
			}
			
			final Dialog dialog = new Dialog (owner, beanTableColumn.getAlias());
			
			//
			if(frameIcon != null) {
				
				dialog.setIconImage(frameIcon);
			}
			
			dialog.getContentPane().add(tablePanel, BorderLayout.CENTER);
			dialog.showExitQuestion(false);
			dialog.setSize(sizeToDialog);
			dialog.setModal(true);
			dialog.centralize();
			
		}else {
			
			JOptionPane.showMessageDialog(null, I18N.component().thereAreNoDetails(), beanTableColumn.getAlias(), JOptionPane.INFORMATION_MESSAGE);
		}
	}
	
	/**
	 * 
	 */
	@Override
	protected void fireEditingStopped() {
	
		super.fireEditingStopped();
	}
	
	/**
	 * @return the value
	 */
	protected final Object getValue() {
	
		return value;
	}
	
	/**
	 * @param value
	 */
	protected final void setValue(final Object value) {
	
		this.value = value;
	}
	
	/**
	 * 
	 */
	@Override
	public Object getCellEditorValue() {
	
		return getValue();
	}
	
	/**
	 * 
	 */
	@Override
	public Component getTableCellEditorComponent(final JTable table, final Object value, final boolean isSelected, final int row, final int column) {
	
		//
		if(firstRun) {
			
			frameIcon = getOwnerWindowIcon(table);
			
			firstRun = false;
		}
		
		beanEditorPanel.getPnlButton().setVisible(true);
		beanEditorPanel.getLabel().setFont(table.getFont());
		
		//
		if(isSelected) {
			
			beanEditorPanel.getPnlButton().setBackground(table.getSelectionBackground());
			beanEditorPanel.getLabel().setForeground(table.getSelectionForeground());
			beanEditorPanel.getLabel().setBackground(table.getSelectionBackground());
			
		}else {
			
			beanEditorPanel.getPnlButton().setBackground(UIManager.getColor("TextField.background"));
			beanEditorPanel.getLabel().setForeground(table.getForeground());
			beanEditorPanel.getLabel().setBackground(UIManager.getColor("TextField.background"));
		}
		
		//
		if(value != null && TypeUtil.isImageIcon(value)) {
			
			final ImageIcon iconValue = (ImageIcon)value;
			
			final int newWidth = iconValue.getIconWidth() > iconValue.getIconHeight() ? DEFAULT_WIDTH : DEFAULT_HEIGHT;
			final int newHeight = iconValue.getIconHeight() > iconValue.getIconWidth() ? DEFAULT_WIDTH : DEFAULT_HEIGHT;
			
			final ImageIcon icon = ImageUtil.resizeImage(iconValue, newWidth, newHeight);
			
			beanEditorPanel.getLabel().setText(null);
			beanEditorPanel.getLabel().setIcon(icon);
			beanEditorPanel.getLabel().setToolTipText(iconValue.getDescription());
			
		}else {
			
			final String label = getLabel(value, table, column);
			
			beanEditorPanel.getLabel().setText(label);
			beanEditorPanel.getLabel().setIcon(null);
			beanEditorPanel.getLabel().setToolTipText(label != null ? null : I18N.component().thereAreNoDetails());
			beanEditorPanel.getPnlButton().setVisible(label != null);
		}
		
		setValue(value);
		
		table.setRowHeight(DEFAULT_HEIGHT);
		
		action(getOwnerWindow(table), (BeanTable<?>)table, column);
		
		return beanEditorPanel;
	}
	
	/**
	 * @param sizeToDialog
	 */
	public void setSizeToDialogInBeanEditor(final Dimension sizeToDialog) {
	
		this.sizeToDialog = sizeToDialog;
	}
	
	/**
	 * 
	 */
	@Override
	public boolean stopCellEditing() {
	
		return super.stopCellEditing();
	}
}
